package net.fdukedom.epicurus.client.ui;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToolBar;

import net.fdukedom.epicurus.client.AppInitializer;
import net.fdukedom.epicurus.client.ClientSession;
import net.fdukedom.epicurus.client.plugin.ClientPluginInterface;
import net.fdukedom.epicurus.client.plugin.PageNotFoundException;
import net.fdukedom.epicurus.core.extensions.menu.MenuExtensionHandler;
import net.fdukedom.epicurus.domain.entity.Plugin;
import net.fdukedom.epicurus.domain.util.DomainException;
import net.fdukedom.epicurus.domain.util.PluginHelper;
import net.fdukedom.epicurus.resource.ExtensionHandler;
import net.fdukedom.epicurus.resource.ResourceDispatcher;

public class GUIDispatcher {
	/**
	 * Index page ID
	 */
	static final public String INDEX_PAGE_ID = "index";

	/**
	 * Instance of class
	 */
	private static GUIDispatcher pageManager;

	/**
	 * Main application frame
	 */
	private static JFrame mainFrame;

	/**
	 * Constructor
	 */
	private GUIDispatcher() {
		mainFrame = new JFrame("Epicurus");

		MainMenuCreator creator = new MainMenuCreator();

		mainFrame.setJMenuBar(creator.createMainMenuBar());
		mainFrame.setSize(500, 300);
		mainFrame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				AppInitializer.finish();
			}
		});
		showPage(null, INDEX_PAGE_ID, null);
	}

	/**
	 * Shows corresponding page
	 * 
	 * @author Alexander Kirakozov
	 */
	private class ShowPageAction extends AbstractAction {
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		/**
		 * Plugin name
		 */
		private String pluginName;

		/**
		 * Location of page (unical ID of page)
		 */
		private String pageLocation;

		/**
		 * Constructor
		 * 
		 * @param pluginName
		 *            plugin name
		 * @param pageLocation
		 *            location of page (unical ID of page)
		 */
		public ShowPageAction(String pluginName, String pageLocation) {
			this.pluginName = pluginName;
			this.pageLocation = pageLocation;
		}

		public void actionPerformed(ActionEvent arg0) {
			GUIDispatcher.getInstance().showPage(pluginName, pageLocation, null);
		}
	}

	/**
	 * @author Alexander Kirakozov
	 */
	private class MainMenuCreator {
		/**
		 * Creates menu bar
		 * 
		 * @param frame
		 *            main frame
		 * @return menu bar
		 */
		public JMenuBar createMainMenuBar() {
			JMenuBar menuBar;
			JMenu menu;
			JMenuItem menuItem;

			menuBar = new JMenuBar();

			menu = new JMenu("File");
			menu.setMnemonic(KeyEvent.VK_F);
			menuBar.add(menu);

			menuItem = new JMenuItem(new ConnectOptionAction(mainFrame,
					"Connection"));
			menuItem.setMnemonic(KeyEvent.VK_C);
			menu.add(menuItem);

			menuItem = new JMenuItem(new PluginAction(mainFrame, "Plugin"));
			menuItem.setMnemonic(KeyEvent.VK_P);
			menu.add(menuItem);

			menu.addSeparator();
			menuItem = new JMenuItem(new AbstractAction("Exit") {
				private static final long serialVersionUID = 1L;

				public void actionPerformed(ActionEvent arg0) {
					AppInitializer.finish();
				}
			});
			menuItem.setMnemonic(KeyEvent.VK_E);
			menu.add(menuItem);

			menu = new JMenu("Help");
			menu.setMnemonic(KeyEvent.VK_H);
			menuBar.add(menu);

			menuItem = new JMenuItem(new AbstractAction("About Epicurus") {
				private static final long serialVersionUID = 1L;

				public void actionPerformed(ActionEvent arg0) {
					showInfoMessage("Epicurus offline client 1.0");
				}
			});
			menuItem.setMnemonic(KeyEvent.VK_A);
			menu.add(menuItem);

			return menuBar;
		}
	}

	/**
	 * Main menu toolbar
	 * 
	 * @author Alexander Kirakozov
	 * 
	 */
	private class MainToolbarCreator {

		public JToolBar createMainMenu() {
			JToolBar toolBar = null;
			List<ExtensionHandler> handlers = ResourceDispatcher.getInstance()
					.getExtensions("core.mainMenu");

			if (handlers != null) {
				Map<String, Object> parameters = new HashMap<String, Object>();
				parameters.put("isLoggedIn", ClientSession.getInstance()
						.IsOpen());
				parameters.put("user", ClientSession.getInstance().getUser());

				for (ExtensionHandler handler : handlers) {
					Map<String, Object> result = handler.execute(parameters);
					if ((Boolean) result
							.get(ExtensionHandler.IS_EXTENSION_VISIBLE)) {
						JButton button = new JButton(
								new ShowPageAction(
										handler.getExtension().getPlugin()
												.getName(),
										(String) result
												.get(MenuExtensionHandler.EXTENSION_ACTION)));
						button.setText((String) result
								.get(MenuExtensionHandler.EXTENSION_TITLE));
						if (toolBar == null) {
							toolBar = new JToolBar();
							toolBar.setFloatable(false);
							toolBar.setRollover(true);
						}

						toolBar.add(button);
					}
				}
			}

			return toolBar;
		}
	}

	/**
	 * Returns instance of this object
	 * 
	 * @return instance of this object
	 */
	public static GUIDispatcher getInstance() {
		if (pageManager == null) {
			pageManager = new GUIDispatcher();
		}

		return pageManager;
	}

	/**
	 * Shows corresponding page
	 * 
	 * @param pluginName
	 *            plgine name
	 * @param pageLocation
	 *            location of page (unical ID of page)
	 */
	public void showPage(String pluginName, String pageLocation, Map<String, Object> parameters) {

		if (pluginName != null) {
			Plugin plugin = ResourceDispatcher.getInstance().findPluginByName(
					pluginName);

			if (plugin != null) {
				ClientPluginInterface plugInst;
				try {
					plugInst = PluginHelper.getInstance().getClientPlugin(
							plugin);
					JPanel pageView = plugInst.createPage(pageLocation, parameters);

					update(pageView);
				} catch (DomainException e) {
					showErrMessage("Client plugin '" + pluginName + "' was not found!");
				} catch (PageNotFoundException e) {
					showErrMessage("The requested resource is not available: \n"
							+ e.getMessage());
				}
			} else {
				showErrMessage("The requested resource is not available: \n"
						+ pageLocation + "\n Plugin: " + pluginName);
			}
		} else {
			try {
				update(createPage(pageLocation));
			} catch (PageNotFoundException e) {
				showErrMessage("The requested resource is not available: \n"
						+ e.getMessage());
			}
		}
	}

	/**
	 * Creates defaulted pages
	 * 
	 * @param pageName
	 * @return
	 */
	public JPanel createPage(String pageName) throws PageNotFoundException {
		if (pageName.equals(INDEX_PAGE_ID)) {
			String message = ResourceDispatcher.getInstance().getBundledValue(
					"bundles.pub.Welcome", "pub.welcome.bodyText");
			JPanel welcomePanel = new JPanel();
			JLabel label = new JLabel(message);

			welcomePanel.add(label);

			return welcomePanel;
		} else {
			throw new PageNotFoundException();
		}
	}

	/**
	 * Show dialog with information message
	 * 
	 * @param message
	 *            message to show
	 */
	public void showInfoMessage(String message) {
		JOptionPane.showMessageDialog(mainFrame, message, "Epicurus"
				+ " information", JOptionPane.INFORMATION_MESSAGE);
	}

	/**
	 * Show dialog with error message
	 * 
	 * @param errMessage
	 *            error discription
	 */
	public void showErrMessage(String errMessage) {
		JOptionPane.showMessageDialog(mainFrame, errMessage, "Epicurus"
				+ " error", JOptionPane.ERROR_MESSAGE);
	}

	/**
	 * Updates main menu view
	 */
	private void update(JPanel pageView) {
		MainToolbarCreator creator = new MainToolbarCreator();
		JToolBar toolbar = creator.createMainMenu();
		JPanel panel = new JPanel();

		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
		if (toolbar != null) {
			panel.add(toolbar);
		}
		panel.add(pageView);

		mainFrame.setContentPane(new JScrollPane(panel));
		mainFrame.setVisible(true);
	}
}
